package com.ds.infra.mq.core.protocol;

import com.ds.infra.mq.core.util.JsonUtil;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
import io.netty.handler.codec.ReplayingDecoder;

import java.nio.charset.StandardCharsets;
import java.util.List;

/**
 * 协议编解码器，用于将消息对象编码为字节流和解码为消息对象。
 *
 * @author WeiShaoying
 */
public class ProtocolCodec {

    public static class Encoder extends MessageToByteEncoder<Message> {
        @Override
        protected void encode(ChannelHandlerContext ctx, Message msg, ByteBuf out) {
            // 协议格式: 总长度(4) + 头部长度(4) + 头部 + 消息体
            byte[] headerBytes = JsonUtil.toJson(msg.getHeader()).getBytes(StandardCharsets.UTF_8);

            // 首先写入总长度：头部长度4字节+头部内容长度+消息体长度
            out.writeInt(4 + headerBytes.length + msg.getBody().length); // 总长度
            out.writeInt(headerBytes.length); // 头部长度
            out.writeBytes(headerBytes); // 头部内容
            out.writeBytes(msg.getBody()); // 消息体
        }
    }

    public static class Decoder extends ReplayingDecoder<Decoder.State> {
        enum State {
            READ_LENGTH,
            READ_CONTENT
        }

        private int totalLength;
        private int headerLength;

        public Decoder() {
            super(State.READ_LENGTH);
        }

        @Override
        protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
            // 根据当前状态执行相应的解码操作
            switch (state()) {
                case READ_LENGTH:
                    // 读取消息总长度
                    totalLength = in.readInt();
                    // 读取消息头长度
                    headerLength = in.readInt();
                    // 切换到读取消息内容的状态
                    checkpoint(State.READ_CONTENT);
                case READ_CONTENT:
                    // 读取消息头内容
                    byte[] headerBytes = new byte[headerLength];
                    in.readBytes(headerBytes);
                    // 将消息头内容反序列化为MessageHeader对象
                    MessageHeader header = JsonUtil.fromJson(new String(headerBytes, StandardCharsets.UTF_8), MessageHeader.class);

                    // 读取消息体内容
                    byte[] body = new byte[totalLength - 4 - headerLength];
                    in.readBytes(body);

                    // 创建Message对象，并设置消息头和消息体
                    Message message = new Message();
                    message.setHeader(header);
                    message.setBody(body);
                    // 将解码后的消息添加到输出列表中
                    out.add(message);
                    // 切换回读取消息长度的状态
                    checkpoint(State.READ_LENGTH);
                    break;
                default:
                    // 抛出非法状态异常
                    throw new IllegalStateException("Invalid state: " + state());
            }
        }

    }
}
